package dao;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import bean.Aktie;
import bean.User;

/**
 * 
 * @author Pascal Kuendig
 * @version 10.07.2013
 *
 */
public class AktieDAO extends AbstractDAO{
	
	private static AktieDAO AktieDAOSingelton;
	
	private AktieDAO(){
		
	}
	
	public static AktieDAO getInstance(){
		if(null == AktieDAOSingelton){
			AktieDAOSingelton = new AktieDAO();
		}
		return AktieDAOSingelton;
	}
	
	public ArrayList<Aktie> getAktienFromUser(User user) throws SQLException, IOException{
		ArrayList<Aktie> aktienFromUser = new ArrayList<Aktie>();
		String sql = super.getDaoPropertie("getAktienFromUser");
		sql = sql.replace("????", user.getBenutzername());
		ResultSet rs = super.executeSelectQueryWithResultSet(sql);
		while (rs.next()){
			aktienFromUser.add(createAktieByResultSet(rs));
		}
		resultSetSchliessen(rs);
		return aktienFromUser;
	}
	
	public ArrayList<Aktie> getAllAvailableAktien() throws IOException, SQLException{
		ArrayList<Aktie> allAvailableAktien = new ArrayList<Aktie>();
		String sql = super.getDaoPropertie("getAllAvailableAktien");
		ResultSet rs = super.executeSelectQueryWithResultSet(sql);
		while (rs.next()){
			allAvailableAktien.add(createAktieByResultSet(rs));
		}
		resultSetSchliessen(rs);
		return allAvailableAktien;
	}
	
	/**
	 * 
	 * @param anzahlAktien
	 * @param newAktie -> wichtige Attribute: Anbietername, Anbieterkuerzel, Nominalpreis (=1.Dividende),Preis)
	 * @return true -> Aktien erfolgreich erstellt
	 * @return false -> Fehler beim erstellen der Aktie
	 * @throws IOException
	 * @throws SQLException
	 */
	public synchronized boolean insertAktieIntoDB(int anzahlAktien,Aktie newAktie) throws IOException, SQLException{
		
		//Check if Anbieter allready exists get AnbieterPK
		int anbieterPK = checkIfAnbieterWithKuerzelExist(newAktie.getAnbieterKuerzel(),newAktie.getAnbieterName());
		if(anbieterPK == 0){
			//create new Anbieter
			String sql = super.getDaoPropertie("createNewAnbieter");
			sql = sql.replace("????", newAktie.getAnbieterName());
			sql = sql.replace("****", newAktie.getAnbieterKuerzel());
			sql = sql.replace("++++", String.valueOf(newAktie.getNominalpreis()));
			super.executeInsertQuery(sql);
			//Get PK from new Anbieter
			ResultSet rs = super.executeSelectQueryWithResultSet(super.getDaoPropertie("getLastInsertedId"));
			if(rs.next()){
				anbieterPK = rs.getInt(1);
				resultSetSchliessen(rs);
			}else{
				resultSetSchliessen(rs);
				return false;
			}
		}
		
		//create Aktie
		for (int i = 0; i < anzahlAktien; i++) {
			if(!createNewAktie(anbieterPK,newAktie.getNominalpreis())){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Setzt den Status privat auf 0
	 * @param userPK
	 * @param anbieterName
	 * @param anbieterKuerzel
	 * @param preis
	 * @param anzahl
	 * @return
	 * @throws IOException
	 * @throws SQLException
	 */
	public synchronized boolean sellAktie(int userPK, String anbieterName, String anbieterKuerzel, double preis, int anzahl) throws IOException, SQLException{
		
		//Get Anzahl Aktien
		String sql = super.getDaoPropertie("countAktienToSell");
		sql = sql.replace("????", String.valueOf(userPK));
		sql = sql.replace("****", String.valueOf(anbieterName));
		sql = sql.replace("++++", String.valueOf(anbieterKuerzel));
		ResultSet rs = super.executeSelectQueryWithResultSet(sql);
		rs.next();
		int size = rs.getInt(1);
		
		//Get zutreffende AktienPKs
		sql = super.getDaoPropertie("selectAktienToSell");
		sql = sql.replace("????", String.valueOf(userPK));
		sql = sql.replace("****", String.valueOf(anbieterName));
		sql = sql.replace("++++", String.valueOf(anbieterKuerzel));
		rs = super.executeSelectQueryWithResultSet(sql);
		
		//Prüfen ob genuegend Datensaetze vorhanden sind um zu verkaufen
		if(size >= anzahl){
			while (rs.next() && anzahl > 0){
				sql = super.getDaoPropertie("sellAktie");
				sql = sql.replace("????", String.valueOf(preis));
				sql = sql.replace("****", String.valueOf(rs.getInt("aktiePK")));
				if(super.executeInsertQuery(sql) == 0){
					resultSetSchliessen(rs);
					return false;
				}
				anzahl = anzahl - 1;
			}
			resultSetSchliessen(rs);
			return true;
		}else{
			resultSetSchliessen(rs);
			return false;
		}
	}
	
	/**
	 * Setzt Status privat auf 1 & preis auf 0
	 * @param idStornoAktie
	 * @return
	 * @throws IOException 
	 * @throws SQLException 
	 */
	public synchronized boolean stornoAktie(int idStornoAktie) throws IOException, SQLException{
		String sql = super.getDaoPropertie("stornoAktie");
		sql = sql.replace("????", String.valueOf(idStornoAktie));
		if(super.executeInsertQuery(sql) == 0){
			return false;
		}
		return true;
	}
	
	/**
	 * Prüft ob der User genügend Geld hat
	 * Setzt eine neue Verbindung in der tbl_portfolio
	 * Setzt das Flag privat auf 1
	 * Belastet den Käufer und schreibt den entsprechenden Betrag dem Verkäufer zu Gute
	 * @param idBuyAktie
	 * @param userPK
	 * @param preisFuerAktie
	 * @throws IOException
	 * @throws SQLException
	 */
	public synchronized boolean buyAktie(int idBuyAktie, int userPK) throws IOException, SQLException{
		
		//SQL aus Propertie lesen
		String sqlGetVerkaeufer = super.getDaoPropertie("getVerkaeufer");
		String sqlSetKontostandVerkaeufer = super.getDaoPropertie("setKontostandVerkaeufer");
		String sqlSetKontostandKaeufer = super.getDaoPropertie("setKontostandKaeufer");
		String sqlDelte = super.getDaoPropertie("buyAktieDelete");
		String sqlUpdate = super.getDaoPropertie("buyAktieUpdate");
		String sqlInsert = super.getDaoPropertie("buyAktieInsert");
		String sqlGetPreisAktie = super.getDaoPropertie("sqlGetPreisAktie");
		String sqlGetKontostandFromUser = super.getDaoPropertie("getKontostandByUserPK");
		String sqlGetPrivatFromAktie = super.getDaoPropertie("getPrivatFromAktie");
		
		//Preis für die aktuelle Aktie auslesen
		sqlGetPreisAktie = sqlGetPreisAktie.replace("????", String.valueOf(idBuyAktie));
		ResultSet rs = super.executeSelectQueryWithResultSet(sqlGetPreisAktie);
		if(!rs.next()){
			resultSetSchliessen(rs);
			return false;
		}
		Double preisFuerAktie = rs.getDouble("preis");
		
		//Prüfen ob genügend Geld vorhanden
		sqlGetKontostandFromUser = sqlGetKontostandFromUser.replace("????", String.valueOf(userPK));
		rs = super.executeSelectQueryWithResultSet(sqlGetKontostandFromUser);
		rs.next();
		if(preisFuerAktie > rs.getDouble("kontostand")){
			//Fals nicht genügend Geld vorhanden: return false
			resultSetSchliessen(rs);
			return false;
		}
		
		//Prüfen ob Aktie noch verfügbar ist
		sqlGetPrivatFromAktie = sqlGetPrivatFromAktie.replace("????", String.valueOf(idBuyAktie));
		rs = super.executeSelectQueryWithResultSet(sqlGetPrivatFromAktie);
		rs.next();
		if(rs.getBoolean("privat")){
			resultSetSchliessen(rs);
			return false;
		}
		
		//Kontostaende aktualisieren
		sqlGetVerkaeufer = sqlGetVerkaeufer.replace("????", String.valueOf(idBuyAktie));
		sqlSetKontostandVerkaeufer = sqlSetKontostandVerkaeufer.replace("????", String.valueOf(preisFuerAktie));
		
		//Verkaufer ausfindig machen
		rs = super.executeSelectQueryWithResultSet(sqlGetVerkaeufer);
		
		//Falls Verkäufer vorhanden -> Preis auf Konto gutschreiben
		if(rs.next()){
			sqlSetKontostandVerkaeufer = sqlSetKontostandVerkaeufer.replace("****", String.valueOf(rs.getInt("userFK")));
			super.executeInsertQuery(sqlSetKontostandVerkaeufer);
		}
		this.resultSetSchliessen(rs);
		
		//Käufer den Preis vom Konto abziehen
		sqlSetKontostandKaeufer = sqlSetKontostandKaeufer.replace("????", String.valueOf(preisFuerAktie));
		sqlSetKontostandKaeufer = sqlSetKontostandKaeufer.replace("****", String.valueOf(userPK));
		super.executeInsertQuery(sqlSetKontostandKaeufer);
				
		
		sqlDelte = sqlDelte.replace("????", String.valueOf(idBuyAktie));
		sqlUpdate = sqlUpdate.replace("????", String.valueOf(idBuyAktie));
		sqlInsert = sqlInsert.replace("****", String.valueOf(userPK));
		sqlInsert = sqlInsert.replace("????", String.valueOf(idBuyAktie));
		
		super.executeInsertQuery(sqlDelte);
		super.executeInsertQuery(sqlUpdate);
		super.executeInsertQuery(sqlInsert);
		return true;
	}
	
	/**
	 * Gibt den Kontostand des Users zurück
	 * @param userPK
	 * @return 0 -> kein Kontostand gefunden
	 * @return aktueller Kontostand
	 * @throws SQLException
	 * @throws IOException
	 */
	public double getKontostandByUserPK(int userPK) throws SQLException, IOException{
		String sqlGetKontostand = super.getDaoPropertie("getKontostandByUserPK");
		sqlGetKontostand = sqlGetKontostand.replace("????", String.valueOf(userPK));
		ResultSet rs = super.executeSelectQueryWithResultSet(sqlGetKontostand);
		rs.next();
		double kontostand = 0;
		kontostand = rs.getDouble("kontostand"); 
		resultSetSchliessen(rs);
		return kontostand;
	}
	
	/**
	 * Berechnet die Dividende für alle Aktien und schreibt diese den Usern zu.
	 * @param min
	 * @param max
	 * @param streuung ->"stark","mittel",schwach"
	 * @return false / true
	 * @throws SQLException 
	 * @throws IOException 
	 */
	public synchronized boolean berechneDividende(int min, int max,String streuung) throws SQLException, IOException{
		
		//Auswerten der Streuung
		int definitiveStreuung;
		switch (streuung) {
		case "stark":
			definitiveStreuung = Dividendenaenderung.STARKE_STREUUNG;
			break;
		case "mittel":
			definitiveStreuung = Dividendenaenderung.MITTLERE_STREUUNG;
			break;
		case "schwach":
			definitiveStreuung = Dividendenaenderung.SCHWACHE_STREUUNG;
			break;
		default:
			return false;
		}
		
		//Alle Anbieter auslesen
		String sqlGetAllAnbieter = super.getDaoPropertie("getDividendePkFromAnbietern");
		ResultSet rs = super.executeSelectQueryWithResultSet(sqlGetAllAnbieter);
		
		//Solange Anbieter vorhanden
		while (rs.next()) {
			//get alte Dividende & berechne Neue
			int neueDividende = Dividendenaenderung.neueDividende((int)rs.getDouble("dividende"), definitiveStreuung, min, max);
			//set neue Dividende
			String sqlSetNewDividende = super.getDaoPropertie("setNewDividende");
			sqlSetNewDividende = sqlSetNewDividende.replace("????", String.valueOf(neueDividende));
			sqlSetNewDividende = sqlSetNewDividende.replace("****", String.valueOf(rs.getInt("anbieterPK")));
			if(super.executeInsertQuery(sqlSetNewDividende) == 0){
				resultSetSchliessen(rs);
				return false;
			}	
		}
				
		String sqlGetUserAndDividende = super.getDaoPropertie("getUserAndDividende");
		rs = super.executeSelectQueryWithResultSet(sqlGetUserAndDividende);
		//Solange Aktien vorhanden
		while(rs.next()){
			//Set Dividende by user
			String sqlSetDividende = super.getDaoPropertie("setKontostandVerkaeufer");
			sqlSetDividende = sqlSetDividende.replace("????", String.valueOf(rs.getDouble("dividende")));
			sqlSetDividende = sqlSetDividende.replace("****", String.valueOf(rs.getInt("userFK")));
			if(super.executeInsertQuery(sqlSetDividende) == 0){
				resultSetSchliessen(rs);
				return false;
			}
		}
		resultSetSchliessen(rs);
		return true;
	}
	
	public ArrayList<String> getAllAnbieter() throws SQLException{
		ArrayList<String> allAnbieter = new ArrayList<String>();
		ResultSet rs = super.executeSelectQueryWithResultSet("SELECT * FROM tbl_anbieter;");
		while (rs.next()){
			allAnbieter.add(rs.getString("name"));
		}
		rs.getStatement().close();
		rs.close();
		return allAnbieter;
	}
	
	private Aktie createAktieByResultSet(ResultSet rs) throws SQLException{
		Aktie aktAktie = new Aktie	(
				rs.getInt("aktiePK"),
				rs.getBoolean("privat"),
				rs.getDouble("preis"),
				rs.getString("benutzername"), 
				rs.getString("name"), 
				rs.getString("kuerzel"), 
				rs.getDouble("nominalpreis"), 
				rs.getDouble("dividende"));
		return aktAktie;
	}
	
	private void resultSetSchliessen(ResultSet rs) throws SQLException{
		rs.getStatement().close();
		rs.close();
	}
	
	/**
	 * Prüft ob Anbieter bereits in DB erfasst
	 * @param anbieterName
	 * @return 0 ->  Anbieter existiert nicht
	 * @return grösser 0 -> anbieterFK
	 * @throws IOException 
	 * @throws SQLException 
	 */
	private int checkIfAnbieterWithKuerzelExist(String anbieterKuerzel, String anbieterName) throws IOException, SQLException{
		int anbieterFK = 0;
		String sql = super.getDaoPropertie("checkIfAnbieterWithKuerzelExist");
		sql = sql.replace("????", anbieterKuerzel);
		sql = sql.replace("****", anbieterName);
		ResultSet rs = super.executeSelectQueryWithResultSet(sql);
		while (rs.next()) {
			anbieterFK = rs.getInt("anbieterPK");
		}
		return anbieterFK;
	}
	
	private synchronized boolean createNewAktie(int anbieterPK, double preis) throws IOException, SQLException{
		String sql = super.getDaoPropertie("createNewAktie");
		sql = sql.replace("????", String.valueOf(anbieterPK));
		sql = sql.replace("****", String.valueOf(preis));
		int returnExecuteQuery = super.executeInsertQuery(sql);
		if (returnExecuteQuery != 0){
			return true;
		}else{
			return false;
		}
	}
}
